package com.ny.nybase.widget.ptr;

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by LiangYu on 2018/1/5.
 */
public class PullToRefreshListView extends AbstractPullToRefreshListView {

    public static final String TAG = PullToRefreshListView.class.getSimpleName();
    public static final int FOOTER_HEIGHT = 30;
    private PullToRefreshWidget header;
    private PullToRefreshWidget footer;
    private com.ny.nybase.widget.ptr.GestureHandler gestureHandler;
    private OnHeaderRefreshListener onHeaderRefreshListener;
    private OnFooterRefreshListener onFooterRefreshListener;
    private boolean headerRefreshEnabled = true;
    private boolean footerRefreshEnabled;
    private boolean footerAdded = false;
    private PtrDataSetObserver dataSetObserver = new PtrDataSetObserver();
    private boolean layout = false;

    public PullToRefreshListView(Context context) {
        super(context);
        init();
    }

    public PullToRefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PullToRefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        if (gestureHandler == null){
            gestureHandler = new PullToRefreshGestureHandler(this);
        }

        /*setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (footer != null){
                    View f = (View)footer;
                    Rect rc = new Rect();
                    boolean b = f.getGlobalVisibleRect(rc);

                    int bottom = ((View) footer).getBottom();
                    int last = getLastVisiblePosition();
                    View parent = ((View)((View) footer).getParent());
                    int pb = (parent != null) ? parent.getBottom() : 0;
                    //log("getGlobalVisibleRect bottom = " + bottom + " last = " + last + " pb = " + pb );

                    if (false){
                        post(new FooterDisplayRunnable());
                    }
                }
            }
        });*/
    }

    public void setHeader(PullToRefreshWidget header){
        if (header == null){
            throw new IllegalArgumentException("header cannot be null.");
        }
        if (!(header instanceof View)){
            throw new IllegalArgumentException("header is not a instance of View.");
        }
        this.header = header;
        addHeaderView((View)header);
        header.setHeight(0);
    }

    public void setFooter(PullToRefreshWidget footer){
        if (footer == null){
            throw new IllegalArgumentException("footer cannot be null.");
        }
        if (!(footer instanceof View)){
            throw new IllegalArgumentException("footer is not a instance of View.");
        }
        this.footer = footer;
        addFooterView((View)footer);
        footer.setHeight(getFooterHeight());

        if (footer instanceof View){
            View v = (View)footer;
            v.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    startFooterRefresh();
                }
            });
        }
    }

    @Override
    public PullToRefreshWidget getHeader(){
        return header;
    }

    @Override
    public PullToRefreshWidget getFooter() {
        return footer;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean result = gestureHandler.dispatchTouchEvent(ev);
        if (!result){
            result = super.dispatchTouchEvent(ev);
        }
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean result = gestureHandler.onTouchEvent(ev);
        if (!result){
            result = super.onTouchEvent(ev);
        }else{
            /*// 如果被拦截了，传一个ACTION_CANCEL给宿主
            MotionEvent me = ev;
            me.setAction(ACTION_CANCEL);
            result = super.onTouchEvent(ev);*/
        }

        return result;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean result = gestureHandler.onInterceptTouchEvent(ev);
        if (!result){
            result = super.onInterceptTouchEvent(ev);
        }
        return result;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        gestureHandler.computeScroll();
    }

    public void setOnHeaderRefreshListener(OnHeaderRefreshListener l){
        this.onHeaderRefreshListener = l;
    }

    public void setOnFooterRefreshListener(OnFooterRefreshListener l){
        this.onFooterRefreshListener = l;
    }

    @Override
    void dispatchHeaderRefresh() {
        if (onHeaderRefreshListener != null){
            onHeaderRefreshListener.onRefresh();
        }
    }

    @Override
    void dispatchFooterRefresh() {
        if (onFooterRefreshListener != null){
            onFooterRefreshListener.onRefresh();
        }
    }

    @Override
    public void startHeaderRefresh() {
        gestureHandler.startHeaderRefresh();
    }

    @Override
    public void startFooterRefresh() {
        gestureHandler.startFooterRefresh();
    }

    @Override
    public void stopHeaderRefresh(){
        gestureHandler.stopHeaderRefresh(true);
    }

    @Override
    public void stopHeaderRefresh(boolean anim){
        gestureHandler.stopHeaderRefresh(anim);
    }

    public void stopFooterRefresh(){
        gestureHandler.stopFooterRefresh(false);
    }

    @Override
    public void setHeaderRefreshEnabled(boolean enabled){
        this.headerRefreshEnabled = enabled;
        if (header != null){
            header.show(enabled);
        }
    }

    @Override
    public void setFooterRefreshEnabled(boolean enabled){
        this.footerRefreshEnabled = enabled;

        // 使能状态改变，高度也要改变
        if (footer != null){
            footer.setHeight(getFooterHeight());
        }
    }

    @Override
    public boolean getHeaderRefreshEnabled() {
        return headerRefreshEnabled;
    }

    @Override
    public boolean getFooterRefreshEnabled() {
        return footerRefreshEnabled;
    }

    @Override
    int getFooterHeight() {
        return getFooterRefreshEnabled() ? PullToRefreshUtil.dip2px(getContext(), FOOTER_HEIGHT) : 0;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        //log("onScrollChanged " + l + " " + t + " " + oldl + " " + oldt);
    }

    @Override
    public void setOnScrollChangeListener(OnScrollChangeListener l) {
        super.setOnScrollChangeListener(l);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (!layout){
            log("displayFooterWhenDataChanged when layout");
            layout = true;
            determineShowFooter();
        }
    }

    private void log(String content){
        if (PullToRefreshUtil.isLogEnabled()){
            Log.i(TAG, content);
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getAdapter().registerDataSetObserver(dataSetObserver);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getAdapter().unregisterDataSetObserver(dataSetObserver);
    }

    private class PtrDataSetObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            displayFooterWhenDataChanged();
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            displayFooterWhenDataChanged();
        }
    }

    void setHeaderState(PullToRefreshWidgetState state){
        getHeader().setState(getHeaderRefreshEnabled() ? state : PullToRefreshWidgetState.Empty);
    }

    void setFooterState(PullToRefreshWidgetState state){
        getFooter().setState(getFooterRefreshEnabled() ? state : PullToRefreshWidgetState.Empty);
    }

    private void displayFooterWhenDataChanged(){
        log("displayFooterWhenDataChanged layout = " + layout);
        determineShowFooter();
    }

    private class FooterDisplayRunnable implements Runnable {

        @Override
        public void run() {
            log("FooterDisplayRunnable execute");
            displayFooter();
        }

        private boolean displayFooter(){
            boolean result = false;

            int fvp = getFirstVisiblePosition();
            int lvp = getLastVisiblePosition();

            if (fvp < 0 || lvp < 0){
                return result;
            }

            View fv = getChildAt(0);
            View lv = getChildAt(lvp - fvp);

            boolean hasScrollbar = true;
            if (fvp == 0 && fv.getTop() == lv.getPaddingTop()
                    && lvp == getCount() - 1 && lv.getHeight() - lv.getPaddingBottom() <= getBottom()){
                hasScrollbar = false;
            }

            boolean footerExists = footer != null;
            log("determine footerExists = " + footerExists + " hasScrollbar = " + hasScrollbar + " footerAdded = " + footerAdded);

            if (footer != null){
                if (hasScrollbar){
                    if (!footerAdded){
                        boolean scrollToBottom = lvp == getCount() - 1;
                        addFooterView((View)footer);
                        if (scrollToBottom){
                            setSelection(getCount() - 1);
                        }
                        footerAdded = true;
                        result = true;
                    }
                    setFooterState(PullToRefreshWidgetState.PullToRefresh);
                }else{
                    if (footerAdded){
                        removeFooterView((View)footer);
                        footerAdded = false;
                        result = true;
                    }
                }
            }
            return result;
        }
    }

    private void determineShowFooter(){
        if (false){
            new FooterDisplayRunnable().run();
        }
    }

    @Override
    public void addFooterView(View v) {
        if (removeFooterView((View)footer)){
            super.addFooterView(v);
            super.addFooterView((View)footer);
        }else{
            super.addFooterView(v);
        }
    }
}
